home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / macros / latex209 / contrib / misc / diagmac.sty < prev    next >
Text File  |  1993-01-11  |  42KB  |  972 lines

  1. %LaTeX style
  2. %MACROS FOR DIAGRAMS - J. C. Reynolds - December 1987
  3.  
  4. %This file contains general-purpose macros for drawing diagrams in LATEX,
  5. %followed by additional macros especially for category-theory diagrams.
  6. %A user's manual is given in the file diagmac.doc, and a test program is
  7. %given in the file diagmactest.tex.
  8.  
  9. %GENERAL-PURPOSE MACROS
  10.  
  11. %The following control symbols may need to be redefined by the user.
  12. \def\diagramunit{1pt}%Redefine only in main program or at the beginning
  13. %      of \diagram or \ctdiagram.
  14. \def\centerheight{3pt}
  15. \def\edgeheaddisp{4pt}
  16. \def\circleheaddisp{2pt}
  17. \def\diameterlist{1pt,2pt,3pt,4pt,5pt,6pt,7pt,8pt,9pt,10pt,11pt,%
  18. 12pt,13pt,14pt,15pt,16pt,20pt,24pt,28pt,32pt,36pt,40pt,}
  19. %Redefine if circle fonts are different.
  20.  
  21. %The following registers store the representation of diagram and/or
  22. %expression programs:
  23. \newdimen\texpr\newdimen\bexpr\newdimen\lexpr\newdimen\rexpr%current rectangle
  24. \newdimen\xcenter\newdimen\ycenter%center point
  25. \newcount\xslope\newcount\yslope%slope of current edge
  26. \newdimen\xstart\newdimen\ystart%start point of current edge
  27. \newdimen\xend\newdimen\yend%end point of current edge
  28. \newdimen\dcircle%diameter of current circle
  29. \newdimen\xcircle\newdimen\ycircle%center of current circle
  30. \newcount\zzisedge%1 if current edge is defined, 0 otherwise
  31. \newcount\zziscircle%1 if current circle is defined, 0 otherwise
  32. \newbox\zzdiagbox%printable material in state
  33. \newdimen\zztotlwidth\newdimen\zztotrwidth%horizontal extent of box material
  34. \newdimen\zztotheight\newdimen\zztotdepth%vertical extent of box material
  35.  
  36. %The following registers are assigned globally to communicate information
  37. %across group boundaries:
  38. \newdimen\zzglobaltotlwidth\newdimen\zzglobaltotrwidth
  39. \newdimen\zzglobaltotheight\newdimen\zzglobaltotdepth
  40. \newdimen\zzglobalxcenter\newdimen\zzglobalycenter
  41. \newcount\zzglobalcnA
  42.  
  43. %The following registers are used locally for various purposes:
  44. \newdimen\zzdmA\newdimen\zzdmB\newdimen\zzdmC\newdimen\zzdmD\newdimen\zzdmE
  45. \newdimen\zzdmF\newdimen\zzdmG\newdimen\zzdmH\newdimen\zzdmI
  46. \newcount\zzcnA\newcount\zzcnB\newcount\zzcnC
  47. \newcount\zzcnD\newcount\zzcnE\newcount\zzcnF
  48. \newcount\zzcnG\newcount\zzcnH\newcount\zzcnI
  49.  
  50. %Hidden macros and other defined control symbols:
  51. %    generally used macros: \zzsetupbox\zznoshadow\zzissue\zzrecordwidth
  52. %        \zzrecordheight\zzmultdiagramunit\zzmakepicture\zzsqroot\zzdistance
  53. %        \zzreduceterms
  54. %    error-checking macros: \zzisnegside\zzcheckedge\zzcheckslope\zzcheckslopea
  55. %        \zzcheckcircle\zzcheckbool\zzcheckposdimen\zzchecknonnegnum
  56. %    used by \vertex: \zzconsvertexlist\zzconsvertexlista\zzconsvertexlistb
  57. %    used by \rect: \zzprocrect
  58. %    used by \hexagon: \zzprochexagon
  59. %    used by \octagon and \rorect: \zzprococtagon
  60. %    used by \diamond: \zzprocdiamond
  61. %    used by \rorect: \zzprocrorecta\zzsearchdiameterlist\zzsearchdiameterlista
  62. %        \zzsearchdiameterlistb
  63. %    used by \outline: \zzoutlinepoly\zzoutlinepolya\zzoutlinepolyb
  64. %        \zzoutlinepolyc
  65. %    used by \outline with \rorect: \zzoutlinerorect
  66. %    used by \setedge: \zzsearchvertexlist\zzsearchvertexlista
  67. %        \zzsearchvertexlistb
  68. %    used by \shadeedge: \zzcastpoly\zzcastpolya\zzcastpolyb
  69. %        \zzcastpolyc\zzcastpolye\zzcastpolyf\zzcastpolyg
  70. %    used by \drawdashedge, \drawdotedge, and \drawsolidedge: \zzdrawedge
  71. %    used by \drawedgehead: \zzdrawedgeheada
  72. %    used by all abutment macros: \zzslidehoriz\zzslidevert\zzclosestpoly
  73. %        \zzclosestpolya\zzclosestpolyb\zzclosestpolyc\zzclosestpolyd
  74. %    used by edge abutment macros: \zzabut
  75. %    used by circle abutment macros: \zzabutcircle\zzabutcirclea\zzrotate
  76. %    used by \shadeedge and all abutment macros: \zzcastpolyd
  77. %    used by \drawcircle: \zzdrawcirclea
  78. %    multiply defined control symbols: \zzvertexlist\zzshadow\zzglobalshadow
  79. %        \zztesta\zztestb\zzvertexitem\zzprocpoly\zzprocrorect\zznext
  80. %        \zzstartshadow\zzendshadow\zzlocalshadow
  81.  
  82. %\diagram creates a box, initializes \zztotlwidth, \zztotrwidth, and
  83. %\zzvertexlist, sets \zzisedge to 0, executes #1, which must be a diagram
  84. %program, and then issues the resulting box, surrounded by kerns so that
  85. %there are no horizontal overhangs.
  86.  
  87. \def\diagram#1{{\setbox\zzdiagbox=\hbox{$\mathsurround=0pt
  88. \zztotlwidth=0pt\zztotrwidth=0pt\def\zzvertexlist{\end}\zzisedge=0\relax
  89. #1\relax\kern\zztotrwidth\global\zzglobaltotlwidth=\zztotlwidth $}
  90. \kern-\zzglobaltotlwidth\box\zzdiagbox}}
  91.  
  92. %\zzsetupbox sets \zzdiagbox to the expression #1 modified by the program #2.
  93. %It also sets \zzglobalxcenter and \zzglobalycenter to the coordinates of
  94. %the center relative to the reference point, \zzglobaltotlwidth to the
  95. %negative of the left overhang width of the expression, and \zzglobalshadow
  96. %to the shadow established by the program, relative to the reference point.
  97. %Before executing #2, it initializes \texpr, \bexpr, \lexpr, \rexpr,
  98. %\xcenter, and \ycenter appropriately, and sets \zziscircle to 0.
  99.  
  100. \def\zzsetupbox#1#2{\setbox\zzdiagbox=\hbox{$\mathsurround=0pt
  101. \setbox\zzdiagbox=\hbox{$\mathsurround=0pt{{#1}}$}
  102. \texpr=\ht\zzdiagbox\bexpr=-\dp\zzdiagbox\rexpr=\wd\zzdiagbox\lexpr=0pt
  103. \xcenter=\rexpr\divide\xcenter by 2\ycenter=\centerheight
  104. \zztotlwidth=0pt\zztotrwidth=\rexpr\def\zzshadow{\zznoshadow0pt,0pt:;}
  105. \zziscircle=0
  106. \box\zzdiagbox\kern-\rexpr
  107. #2\relax
  108. \global\zzglobalxcenter=\xcenter\global\zzglobalycenter=\ycenter
  109. \global\zzglobaltotlwidth=\zztotlwidth\kern\zztotrwidth
  110. \global\let\zzglobalshadow=\zzshadow
  111. $}}
  112.  
  113. %\zznoshadow is a dummy shadowing routine that gives an error when executed.
  114.  
  115. \def\zznoshadow#1,#2:;{\errmessage{ATTEMPT TO OUTLINE OR ABUT AN EXPRESSION
  116. WITH NO SHADOW}}
  117.  
  118. %\leftghost (\rightghost) sets \xcenter to \lexpr plus (\rexpr minus)
  119. %half of the width of its argument.
  120.  
  121. \def\leftghost#1{\setbox\zzdiagbox=\hbox{$\mathsurround=0pt{{#1}}$}
  122. \xcenter=\wd\zzdiagbox\divide\xcenter by 2\advance\xcenter by \lexpr}
  123.  
  124. \def\rightghost#1{\setbox\zzdiagbox=\hbox{$\mathsurround=0pt{{#1}}$}
  125. \xcenter=\wd\zzdiagbox\divide\xcenter by -2\advance\xcenter by \rexpr}
  126.  
  127. %\zzissue should be executed after \zzsetupbox.  It issues the contents of
  128. %\zzdiagbox with its center placed at \zzdmA, \zzdmB (which are modified),
  129. %and adjusts \zztotlwidth and \zztotrwidth appropriately.
  130.  
  131. \def\zzissue{\advance\zzdmA by -\zzglobalxcenter
  132. \advance\zzdmB by -\zzglobalycenter
  133. \zzdmC=\zzdmA\advance\zzdmC by \wd\zzdiagbox
  134. \zzdmD=\zzdmA\advance\zzdmD by \zzglobaltotlwidth
  135. \zzrecordwidth\zzdmD\zzdmC
  136. \kern\zzdmA\raise\zzdmB\box\zzdiagbox\kern-\zzdmC}
  137.  
  138. %\zzrecordwidth adjusts \zztotlwidth to be the minimum of its previous value
  139. %and #1, and adjusts \zztotrwidth to be the maximum of its previous value
  140. %and #2.
  141.  
  142. \def\zzrecordwidth#1#2{\relax\ifdim#1<\zztotlwidth\relax\zztotlwidth=#1\fi
  143. \ifdim\zztotrwidth<#2\relax\zztotrwidth=#2\fi}
  144.  
  145. %\zzrecordheight adjusts \zztotheight to be the maximum of its previous value
  146. %and #1, and adjusts \zztotdepth to be the minimum of its previous value
  147. %and #2.
  148.  
  149. \def\zzrecordheight#1#2{\relax\ifdim\zztotheight<#1\relax\zztotheight=#1\fi
  150. \ifdim#2<\zztotdepth\relax\zztotdepth=#2\fi}
  151.  
  152. %\placed executes \zzsetupbox{#3}{#4} and issues the contents of the resulting
  153. %\zzdiagbox with its center placed at #1, #2 (which must be dimensions).
  154. %\place is similar except that #1, #2 must be integer multiples of
  155. %\diagramunit.
  156.  
  157. \def\placed#1#2#3#4{\zzsetupbox{#3}{#4}\zzdmA=#1\zzdmB=#2\zzissue}
  158.  
  159. \def\place#1,#2:#3#4{\zzsetupbox{#3}{#4}\zzmultdiagramunit\zzdmA{#1}
  160. \zzmultdiagramunit\zzdmB{#2}\zzissue}
  161.  
  162. %\zzmultdiagramunit sets #1 to #2 times \diagramunit.
  163.  
  164. \def\zzmultdiagramunit#1#2{#1=\diagramunit\multiply#1 by #2\relax}
  165.  
  166. %\vertex#1,#2:#3#4 executes \zzsetupbox{#3}{#4}, issues the contents of the
  167. %resulting \zzdiagbox with its center placed at #1, #2 times \diagramunit,
  168. %adjusts \zztotlwidth and \zztotrwidth appropriately, and adds \zzglobalshadow
  169. %to the beginning of \zzvertexlist (unless \zzglobalshadow is a call of
  170. %\zznoshadow) after readjusting the shadow to be relative
  171. %to the coordinates of the enclosing box.
  172.  
  173. \def\vertex#1,#2:#3#4{\place{#1},{#2}:{#3}{#4}\zzcnA=#1\zzcnB=#2\relax
  174. \expandafter\zzconsvertexlist\zzglobalshadow}
  175.  
  176. \def\zzconsvertexlist#1#2,#3:#4;{\def\zztesta{#1}\def\zztestb{\zznoshadow}
  177. \ifx\zztesta\zztestb\else
  178. \advance\zzdmA by #2\advance\zzdmB by #3\relax
  179. \edef\zzvertexitem{\the\zzcnA,\the\zzcnB:\noexpand #1\the\zzdmA,\the\zzdmB:#4;}
  180. \expandafter\zzconsvertexlista\zzvertexlist\fi}
  181.  
  182. \def\zzconsvertexlista{\expandafter\zzconsvertexlistb\zzvertexitem}
  183.  
  184. \def\zzconsvertexlistb#1\end{\def\zzvertexlist{#1\end}}
  185.  
  186. %\rect, \hexagon, \octagon, and \diamond (and, roughly speaking, \rorect)
  187. %are polygon descriptors.  A polygon descriptor defines \zzshadow to have
  188. % the form \somecontrolsymbol #1,#2:#3; such that executing
  189. %\zzshadow causes a call \zzprocpoly{#1}{#2}{<edgelist>}, where <edgelist>
  190. %depends only upon the parameter #3.  Here #1, #2 are the
  191. %coordinates of a vertex of a convex polygon, and <edgelist> is a list of
  192. %triples describing the edges of the polygon in clockwise order.  If an
  193. %edge is x = xs.t + x0, y = ys.t + y0 for 0 < t < tend (with the start at
  194. %t = 0 and the end at t = tend when the edge is traversed in clockwise
  195. %order) the the trip describing the edge is {xs}{ys}{tend}, where xs and
  196. %ys are numbers (the brackets may be omitted for single-digit numbers)
  197. %and tend is a dimension. xs and ys must have a least common divisor of one.
  198.  
  199. \def\rect{\zzdmC=\rexpr\advance\zzdmC by -\lexpr
  200. \zzdmD=\texpr\advance\zzdmD by -\bexpr
  201. \zzisnegside{\zzdmC}{RECT}\zzisnegside{\zzdmD}{RECT}
  202. \edef\zzshadow{\noexpand\zzprocrect
  203. \the\lexpr,\the\texpr:\the\zzdmC,\the\zzdmD;}}
  204.  
  205. \def\zzprocrect#1,#2:#3,#4;{\zzprocpoly
  206. {#1}{#2}{10{#3}0{-1}{#4}{-1}0{#3}01{#4}}}
  207.  
  208. \def\zzisnegside#1#2{\relax\ifdim#1<0pt\errmessage
  209. {#2 WITH NEGATIVE SIDE}\fi}
  210.  
  211. \def\hexagon{\zzdmC=\rexpr\advance\zzdmC by -\lexpr
  212. \zzdmD=\texpr\advance\zzdmD by -\bexpr\divide\zzdmD by 4
  213. \zzisnegside{\zzdmC}{HEXAGON}\zzisnegside{\zzdmD}{HEXAGON}
  214. \edef\zzshadow{\noexpand\zzprochexagon
  215. \the\lexpr,\the\texpr:\the\zzdmC,\the\zzdmD;}}
  216.  
  217. \def\zzprochexagon#1,#2:#3,#4;{\zzprocpoly{#1}{#2}
  218. {10{#3}1{-2}{#4}{-1}{-2}{#4}{-1}0{#3}{-1}2{#4}12{#4}}}
  219.  
  220. \def\octagon#1{\zzdmC=#1\zzdmD=\zzdmC\multiply\zzdmD by -2\zzdmE=\zzdmD
  221. \advance\zzdmD by \rexpr\advance\zzdmD by -\lexpr
  222. \advance\zzdmE by \texpr\advance\zzdmE by -\bexpr
  223. \zzdmF=\lexpr\advance\zzdmF by \zzdmC
  224. \zzisnegside{\zzdmC}{OCTAGON}\zzisnegside{\zzdmD}{OCTAGON}
  225. \zzisnegside{\zzdmE}{OCTAGON}
  226. \edef\zzshadow{\noexpand\zzprococtagon
  227. \the\zzdmF,\the\texpr:\the\zzdmC,\the\zzdmD,\the\zzdmE;}}
  228.  
  229. \def\zzprococtagon#1,#2:#3,#4,#5;{\zzprocpoly{#1}{#2}
  230. {10{#4}1{-1}{#3}0{-1}{#5}{-1}{-1}{#3}{-1}0{#4}{-1}1{#3}01{#5}11{#3}}}
  231.  
  232. \def\diamond{\zzdmC=\texpr\advance\zzdmC by -\bexpr
  233. \advance\zzdmC by \rexpr\advance\zzdmC by -\lexpr\divide\zzdmC by 2
  234. \zzdmD=\lexpr\advance\zzdmD by \rexpr\divide\zzdmD by 2
  235. \zzdmE=\texpr\advance\zzdmE by \bexpr\divide\zzdmE by 2\advance\zzdmE by \zzdmC
  236. \zzisnegside{\zzdmC}{DIAMOND}
  237. \edef\zzshadow{\noexpand\zzprocdiamond
  238. \the\zzdmD,\the\zzdmE:\the\zzdmC;}}
  239.  
  240. \def\zzprocdiamond#1,#2:#3;{\zzprocpoly{#1}{#2}
  241. {1{-1}{#3}{-1}{-1}{#3}{-1}1{#3}11{#3}}}
  242.  
  243. \def\rorect#1#2#3{\zzcheckposdimen{#1}{FIRST}{RORECT}
  244. \zzcheckbool{#2}{SECOND}{RORECT}\zzcheckbool{#3}{THIRD}{RORECT}
  245. \zzdmD=\rexpr\advance\zzdmD by -\lexpr\zzdmE=\texpr\advance\zzdmE by -\bexpr
  246. \zzdmC=#1\relax
  247. \ifnum#2=1\relax\ifdim\zzdmD>\zzdmC\relax\zzdmC=\zzdmD\fi\fi
  248. \ifnum#3=1\relax\ifdim\zzdmE>\zzdmC\relax\zzdmC=\zzdmE\fi\fi
  249. \expandafter\zzsearchdiameterlist\diameterlist\end\zzdmC=\zzdmF\relax
  250. \ifdim\zzdmC>\zzdmD\relax\zzdmD=\zzdmC\fi
  251. \ifdim\zzdmC>\zzdmE\relax\zzdmE=\zzdmC\fi
  252. \zzdmF=\lexpr\advance\zzdmF by \rexpr\divide\zzdmF by 2
  253. \zzdmG=\bexpr\advance\zzdmG by \texpr\divide\zzdmG by 2
  254. \edef\zzshadow{\noexpand\zzprocrorect
  255. \the\zzdmF,\the\zzdmG:\the\zzdmC,\the\zzdmD,\the\zzdmE;}}
  256.  
  257. \def\zzsearchdiameterlist#1{\def\zztesta{#1}\def\zztestb{\end}
  258. \ifx\zztesta\zztestb\let\zznext=\zzsearchdiameterlista
  259. \else\let\zznext=\zzsearchdiameterlistb\fi\zznext #1}
  260.  
  261. \def\zzsearchdiameterlista#1\end{}
  262.  
  263. \def\zzsearchdiameterlistb#1,{\zzdmF=#1\relax
  264. \ifdim\zzdmF<\zzdmC\relax\let\zznext=\zzsearchdiameterlist
  265. \else\let\zznext=\zzsearchdiameterlista\fi\zznext}
  266.  
  267. %\outline uses \zzoutlinepoly and \zzoutlinerorect to issue an outline of
  268. %the shadow.
  269.  
  270. \def\outline{\def\zzprocpoly{\zzoutlinepoly}
  271. \def\zzprocrorect{\zzoutlinerorect}\zzshadow}
  272.  
  273. %\zzmakepicture encapsulates all usage of the LATEX picture facility.
  274.  
  275. \def\zzmakepicture#1{{\setlength{\unitlength}{1sp}\begin{picture}(0,0)
  276. #1\relax
  277. \global\zzglobaltotlwidth=\zztotlwidth\global\zzglobaltotrwidth=\zztotrwidth
  278. \global\zzglobaltotheight=\zztotheight\global\zzglobaltotdepth=\zztotdepth
  279. \end{picture}\vrule height\zzglobaltotheight depth-\zzglobaltotdepth width0pt}
  280. \zztotlwidth=\zzglobaltotlwidth\zztotrwidth=\zzglobaltotrwidth}
  281.  
  282. \def\zzoutlinepoly#1#2#3{\zzmakepicture{\zzdmA=#1\zzdmB=#2\relax
  283. \zztotheight=\zzdmB\zztotdepth=\zzdmB\zzoutlinepolya #3\end}}
  284.  
  285. \def\zzoutlinepolya#1{\def\zztesta{#1}\def\zztestb{\end}
  286. \ifx\zztesta\zztestb\let\zznext=\zzoutlinepolyb
  287. \else\let\zznext=\zzoutlinepolyc\fi\zznext {#1}}
  288.  
  289. \def\zzoutlinepolyb#1{}
  290.  
  291. \def\zzoutlinepolyc#1#2#3{\zzrecordwidth\zzdmA\zzdmA\zzrecordheight\zzdmB\zzdmB
  292. \zzdmE=#3\multiply\zzdmE by #1\zzdmF=#3\multiply\zzdmF by #2\relax
  293. \zzcnA=\zzdmA\zzcnB=\zzdmB\relax
  294. \ifnum #1=0\relax\zzcnC=\zzdmF\else\zzcnC=\zzdmE\fi
  295. \ifnum\zzcnC<0\relax\zzcnC=-\zzcnC\fi
  296. \put(\zzcnA,\zzcnB){\line(#1,#2){\zzcnC}}
  297. \advance\zzdmA by \zzdmE\advance\zzdmB by \zzdmF
  298. \zzoutlinepolya}
  299.  
  300. \def\zzoutlinerorect#1,#2:#3,#4,#5;{\zzmakepicture{
  301. \zzdmA=#1\zzdmB=#2\zzdmC=#3\zzdmD=#4\zzdmE=#5
  302. \zzcnA=\zzdmA\zzcnB=\zzdmB\zzcnC=\zzdmC\zzcnD=\zzdmD\zzcnE=\zzdmE
  303. \ifnum\zzcnD=\zzcnC\relax\put(\zzcnA,\zzcnB){\oval(\zzcnD,\zzcnE)}
  304. \else\ifnum\zzcnE=\zzcnC\relax\put(\zzcnA,\zzcnB){\oval(\zzcnD,\zzcnE)}
  305. \else\advance\zzcnE by -\zzcnC
  306. \zzcnF=\zzcnE\divide\zzcnF by 2\advance\zzcnF by \zzcnB
  307. \put(\zzcnA,\zzcnF){\oval(\zzcnD,\zzcnC)[t]}
  308. \advance\zzcnF by -\zzcnE
  309. \put(\zzcnA,\zzcnF){\oval(\zzcnD,\zzcnC)[b]}
  310. \zzcnC=\zzcnD\divide\zzcnC by 2\advance\zzcnA by \zzcnC
  311. \put(\zzcnA,\zzcnF){\line(0,1){\zzcnE}}
  312. \advance\zzcnA by -\zzcnD
  313. \put(\zzcnA,\zzcnF){\line(0,1){\zzcnE}}\fi\fi
  314. \zztotheight=\zzdmE\divide\zztotheight by 2\advance\zztotheight by \zzdmB
  315. \zztotdepth=\zztotheight\advance\zztotdepth by -\zzdmE
  316. \zzdmC=\zzdmD\divide\zzdmC by -2\advance\zzdmC by \zzdmA
  317. \advance\zzdmD by \zzdmC\zzrecordwidth\zzdmC\zzdmD}}
  318.  
  319. %\border, \borderto, and \symmetrize adjust the current rectangle.
  320.  
  321. \def\border#1#2{\advance\texpr by #2\advance\bexpr by -#2
  322. \advance\lexpr by -#1\advance\rexpr by #1}
  323.  
  324. \def\borderto#1#2{\zzdmA=\rexpr\advance\zzdmA by -\lexpr\relax
  325. \ifdim#1>\zzdmA\relax\advance\zzdmA by -#1\divide\zzdmA by 2
  326. \advance\rexpr by -\zzdmA\advance\lexpr by \zzdmA\fi
  327. \zzdmA=\texpr\advance\zzdmA by -\bexpr\relax
  328. \ifdim#2>\zzdmA\relax\advance\zzdmA by -#2\divide\zzdmA by 2
  329. \advance\texpr by -\zzdmA\advance\bexpr by \zzdmA\fi}
  330.  
  331. \def\symmetrize{\zzdmA=\texpr\advance\zzdmA by -\ycenter
  332. \zzdmB=\ycenter\advance\zzdmB by -\bexpr\relax
  333. \ifdim\zzdmA<\zzdmB\relax\zzdmA=\zzdmB\fi
  334. \texpr=\ycenter\advance\texpr by \zzdmA
  335. \bexpr=\ycenter\advance\bexpr by -\zzdmA}
  336.  
  337. %\setedge#1,#2,#3,#4: accepts four numbers (giving dimensions as multiples of
  338. %\diagramunit).  It sets \xstart, \ystart, \xend, \yend to #1, #2, #3,
  339. %#4, each multiplied by \diagramunit, and \xslope, \yslope to numbers
  340. % giving the slope of the line from \xstart, \ystart to \xend, \yend,
  341. %reduced to have a least common divisor.  It uses \zzsearchvertexlist to set
  342. %\zzstartshadow (\zzendshadow) to the \zzshadow stored on \zzvertexlist with
  343. %coordinates #1, #2 (#3, #4).  It sets \zzisedge to 1.
  344.  
  345. \def\setedge#1,#2,#3,#4:{\zzcnA=#1\zzcnB=#2
  346. \zzmultdiagramunit\xstart\zzcnA\zzmultdiagramunit\ystart\zzcnB
  347. \expandafter\zzsearchvertexlist\zzvertexlist
  348. \let\zzstartshadow=\zzshadow
  349. \zzcnA=#3\zzcnB=#4
  350. \zzmultdiagramunit\xend\zzcnA\zzmultdiagramunit\yend\zzcnB
  351. \expandafter\zzsearchvertexlist\zzvertexlist
  352. \let\zzendshadow=\zzshadow
  353. \xslope=#3\advance\xslope by -#1\relax
  354. \yslope=#4\advance\yslope by -#2\relax
  355. \zzreduceterms\xslope\yslope{START AND END OF EDGE ARE BOTH THE SAME}
  356. \xslope=\zzcnC\yslope=\zzcnD\zzisedge=1}
  357.  
  358. %\zzreduceterms sets \zzcnC and \zzcnD to the results of dividing the numbers
  359. % #1 and #2 by their greatest common divisor.  The error message #3 is given
  360. %if #1 and #2 are both zero.
  361.  
  362. \def\zzreduceterms#1#2#3{{
  363. \ifnum#1<0\relax\zzcnA=-#1\else\zzcnA=#1\fi
  364. \ifnum#2<0\relax\zzcnB=-#2\else\zzcnB=#2\fi
  365. \loop\ifnum\zzcnB>0\relax
  366. \zzcnC=\zzcnA\divide\zzcnC by \zzcnB\multiply\zzcnC by -\zzcnB
  367. \advance\zzcnC by \zzcnA\zzcnA=\zzcnB\zzcnB=\zzcnC
  368. \repeat\relax
  369. \ifnum\zzcnA=0\errmessage{#3}\fi
  370. \global\zzglobalcnA=\zzcnA}
  371. \zzcnC=#1\divide\zzcnC by \zzglobalcnA\zzcnD=#2\divide\zzcnD by \zzglobalcnA}
  372.  
  373. %\zzsearchvertexlist\zzvertexlist searches \zzvertexlist for an entry of the
  374. %form #1,#2:#3; for which #1 = \zzcnA and #2 = \zzcnB.  If such an entry is
  375. %found, \zzshadow is defined to be #3;.  Otherwise, \zzshadow is defined to be
  376. %\zzdmE=\zzdmA\zzdmF=\zzdmB.
  377.  
  378. \def\zzsearchvertexlist#1{\def\zztesta{#1}\def\zztestb{\end}
  379. \ifx\zztesta\zztestb\def\zzshadow{\zzdmE=\zzdmA\zzdmF=\zzdmB}
  380. \let\zznext=\zzsearchvertexlista
  381. \else\let\zznext=\zzsearchvertexlistb\fi\zznext #1}
  382.  
  383. \def\zzsearchvertexlista#1\end{}
  384.  
  385. \def\zzsearchvertexlistb#1,#2:#3;{\relax
  386. \ifnum\zzcnA=#1\relax\ifnum\zzcnB=#2\relax
  387. \def\zzshadow{#3;}\let\zznext=\zzsearchvertexlista
  388. \else\let\zznext=\zzsearchvertexlist\fi
  389. \else\let\zznext=\zzsearchvertexlist\fi\zznext}
  390.  
  391. %\shadeedge shades the start and end of the current edge, changing \xstart,
  392. %\ystart, \xend, \yend.
  393.  
  394. \def\shadeedge{\zzcheckedge{SHADE}
  395. \def\zzprocpoly{\zzcastpoly}\def\zzprocrorect{\zzprocrorecta}
  396. \zzdmA=\xstart\zzdmB=\ystart\zzcnA=\xslope\zzcnB=\yslope
  397. \zzstartshadow\xstart=\zzdmE\ystart=\zzdmF
  398. \zzdmA=\xend\zzdmB=\yend\zzcnA=-\xslope\zzcnB=-\yslope
  399. \zzendshadow\xend=\zzdmE\yend=\zzdmF}
  400.  
  401. \def\zzcheckedge#1{\relax\ifnum\zzisedge=0\relax\errmessage
  402. {ATTEMPT TO #1 NONEXISTENT EDGE}\fi}
  403.  
  404. %\zzprocrorecta is used as the definition of \zzprocrorect within \shadeedge
  405. %and \zzabut.  It causes a rounded rectangle to be treated as the
  406. %circumscribed octagon for purposes of shadowing or abutment.
  407.  
  408. \def\zzprocrorecta#1,#2:#3,#4,#5;{\zzdmC=#3
  409. \multiply\zzdmC by 53\divide\zzdmC by 181
  410. \zzdmD=\zzdmC\multiply\zzdmD by -2\zzdmE=\zzdmD
  411. \advance\zzdmD by #4\advance\zzdmE by #5
  412. \zzdmF=#4\divide\zzdmF by -2\advance\zzdmF by #1\advance\zzdmF by \zzdmC
  413. \zzdmG=#5\divide\zzdmG by 2\advance\zzdmG by #2
  414. \edef\zzlocalshadow{\noexpand\zzprococtagon
  415. \the\zzdmF,\the\zzdmG:\the\zzdmC,\the\zzdmD,\the\zzdmE;}
  416. \zzlocalshadow}
  417.  
  418. %\zzcastpoly computes the outgoing intersection of a directed line,
  419. %x = xs.t+x0, y = ys.t+y0 with a convex polygon.  It is called
  420. %by defining \zzprocpoly to be \zzcastpoly, setting \zzdmA, \zzdmB, \zzcnA,
  421. %\zzcnB to x0, y0, xs, ys, and executing \zzshadow, which must have been
  422. %defined by a polygon descriptor.  The result is left in \zzdmE, \zzdmF.
  423. %If the directed line does not intersect the polygon, the result is the
  424. %point on the line that is closest to the polygon.
  425.  
  426. \def\zzcastpoly#1#2#3{\zzdmC=#1\zzdmD=#2\zzcnC=0
  427. \zzcastpolya #3\end}
  428.  
  429. \def\zzcastpolya#1{\def\zztesta{#1}\def\zztestb{\end}
  430. \ifx\zztesta\zztestb\let\zznext=\zzcastpolyg
  431. \else\let\zznext=\zzcastpolyc\fi\zznext {#1}}
  432.  
  433. \def\zzcastpolyb#1\end{\zzcnC=\zzcnA\multiply\zzcnC by \zzcnA
  434. \zzcnD=\zzcnB\multiply\zzcnD by \zzcnB\advance\zzcnC by \zzcnD
  435. \zzdmE=\zzdmC\advance\zzdmE by -\zzdmA\multiply\zzdmE by \zzcnA
  436. \zzdmF=\zzdmD\advance\zzdmF by -\zzdmB\multiply\zzdmF by \zzcnB
  437. \advance\zzdmE by \zzdmF\divide\zzdmE by \zzcnC\zzdmF=\zzdmE
  438. \multiply\zzdmE by \zzcnA\advance\zzdmE by \zzdmA
  439. \multiply\zzdmF by \zzcnB\advance\zzdmF by \zzdmB}
  440.  
  441.  
  442. \def\zzcastpolyc#1#2#3{\zzcnD=\zzcnB\multiply\zzcnD by #1\relax
  443. \zzcnE=\zzcnA\multiply\zzcnE by #2\relax\advance\zzcnD by -\zzcnE\relax
  444. \ifnum\zzcnD>0\relax
  445. \ifnum\zzcnC=2\zzcastpolyd{#1}{#2}{#3}\let\zznext=\zzcastpolya\else
  446. \zzdmE=\zzdmA\advance\zzdmE by -\zzdmC\multiply\zzdmE by \zzcnB
  447. \zzdmF=\zzdmB\advance\zzdmF by -\zzdmD\multiply\zzdmF by \zzcnA
  448. \advance\zzdmE by -\zzdmF\divide\zzdmE by \zzcnD\relax
  449. \ifdim\zzdmE>#3\relax\zzcnC=3\zzcastpolyd{#1}{#2}{#3}\let\zznext=\zzcastpolya
  450. \else\ifnum\zzcnC=3\zzcastpolyf{#1}{#2}\let\zznext=\zzcastpolye\else
  451. \ifdim\zzdmE<0pt\relax
  452. \ifnum\zzcnC=1\let\zznext=\zzcastpolyb\else
  453. \zzcnC=2\zzcastpolyd{#1}{#2}{#3}\let\zznext=\zzcastpolya\fi
  454. \else\zzcastpolyf{#1}{#2}\let\zznext=\zzcastpolye\fi\fi\fi\fi
  455. \else\ifnum\zzcnC=3\let\zznext=\zzcastpolyb
  456. \else\zzcnC=1\zzcastpolyd{#1}{#2}{#3}\let\zznext=\zzcastpolya\fi\fi
  457. \zznext}
  458.  
  459. \def\zzcastpolyd#1#2#3{
  460. \zzdmE=#3\multiply\zzdmE by #1\advance\zzdmC by \zzdmE
  461. \zzdmE=#3\multiply\zzdmE by #2\advance\zzdmD by \zzdmE}
  462.  
  463. \def\zzcastpolye#1\end{}
  464.  
  465. \def\zzcastpolyf#1#2{\zzdmF=\zzdmE
  466. \multiply\zzdmE by #1\relax\advance\zzdmE by \zzdmC
  467. \multiply\zzdmF by #2\relax\advance\zzdmF by \zzdmD}
  468.  
  469. \def\zzcastpolyg#1{\zzcastpolyb\end}
  470.  
  471. %\shiftedge changes \xstart, \ystart, \xend, \yend so as to displace
  472. %the edge from \xstart, \ystart to \xend, \yend by a vector of length
  473. %#1 (a dimension) that is rotated 90 degrees counterclockwise from the edge.
  474.  
  475. \def\shiftedge#1{\zzcheckedge{SHIFT}
  476. \zzdistance\xslope\yslope
  477. \zzdmA=#1\multiply\zzdmA by 100\divide\zzdmA by \zzglobalcnA\zzdmB=\zzdmA
  478. \multiply\zzdmA by -\yslope\multiply\zzdmB by \xslope
  479. \advance\xstart by \zzdmA \advance\xend by \zzdmA
  480. \advance\ystart by \zzdmB \advance\yend by \zzdmB}
  481.  
  482. %\zzsqroot#1 accepts an integer and sets \zzglobalcnA to the integer part
  483. %of its square root.  It works for numbers up to at least 1,000,000,000.
  484.  
  485. \def\zzsqroot#1{{\zzcnA=#1
  486. %x is \zzcnA, y is \zzcnB, n is \zzcnC, z is \zzcnD
  487. \zzcnC=0\zzcnD=1
  488. \loop\zzcnE=\zzcnA\divide\zzcnE by \zzcnD\advance\zzcnE by 1
  489. \relax\ifnum\zzcnD<\zzcnE\relax
  490. \advance \zzcnC by 1\multiply\zzcnD by 2
  491. \repeat
  492. \zzcnB=0
  493. \loop\ifnum\zzcnC>0\relax
  494. \advance\zzcnC by -1\divide\zzcnD by 2
  495. \zzcnE=\zzcnB\advance\zzcnE by \zzcnD\multiply\zzcnE by \zzcnE\relax
  496. \ifnum\zzcnA<\zzcnE\relax\else\advance\zzcnB by \zzcnD\fi
  497. \repeat
  498. \global\zzglobalcnA=\zzcnB}}
  499.  
  500. %\zzdistance#1#2 accepts two integers and sets \zzglobalcnA to 100 times
  501. %the square root of the sum of their squares.
  502.  
  503. \def\zzdistance#1#2{{\zzcnA=#1\multiply\zzcnA by \zzcnA
  504. \zzcnB=#2\multiply\zzcnB by \zzcnB
  505. \advance\zzcnA by \zzcnB\multiply\zzcnA by 10000
  506. \zzsqroot\zzcnA}}
  507.  
  508. %\drawdashedge, \drawdotedge, or \drawsolidedge draws a dashed, dotted, or
  509. %solid line along the current edge.
  510.  
  511. \def\drawdashedge#1#2#3#4{\zzcnA=1\zzdmA=#1\zzdmB=#2
  512. \zzcheckposdimen\zzdmA{FIRST}{DRAWDASHEDGE}
  513. \zzcheckposdimen\zzdmB{SECOND}{DRAWDASHEDGE}
  514. \zzchecknonnegnum{#3}{THIRD}{DRAWDASHEDGE}
  515. \zzchecknonnegnum{#4}{FOURTH}{DRAWDASHEDGE}
  516. \zzcnI=#3\relax\advance\zzcnI by #4\relax
  517. \ifnum\zzcnI>0\else\errmessage
  518. {SUM OF THIRD AND FOURTH PARAMETERS OF DRAWDASHEDGE MUST BE POSITIVE}\fi
  519. \advance\zzdmB by \zzdmA
  520. \zzdrawedge{\advance\zzcnC by -\zzcnD
  521. \zzcnG=\zzcnC\divide\zzcnG by \zzcnE\relax
  522. \ifnum\zzcnG>0\relax
  523. \zzcnH=\zzcnG\multiply\zzcnH by \zzcnE\advance\zzcnC by -\zzcnH
  524. \zzcnH=\zzcnI\multiply\zzcnH by \zzcnG
  525. \advance\zzcnH by #3\divide\zzcnC by \zzcnH
  526. \zzcnH=#3\multiply\zzcnH by \zzcnC\advance\zzcnD by \zzcnH
  527. \multiply\zzcnC by \zzcnI\advance\zzcnE by \zzcnC
  528. \else\advance\zzcnD by \zzcnC\fi}
  529. {\line(\xslope,\yslope){\zzcnD}}}
  530.  
  531. \def\zzcheckposdimen#1#2#3{\relax\ifdim#1>0pt\else\errmessage{
  532. #2 PARAMETER OF #3 MUST BE POSITIVE}\fi}
  533.  
  534. \def\zzchecknonnegnum#1#2#3{\relax\ifnum#1<0\relax\errmessage{
  535. #2 PARAMETER OF #3 MUST BE NONNEGATIVE}\fi}
  536.  
  537. \def\drawdotedge#1#2{\zzcnA=0\zzdmA=0pt\zzdmB=#1
  538. \zzcheckposdimen\zzdmB{}{DRAWDOTEDGE}\zzcheckbool{#2}{SECOND}{DRAWDOTEDGE}
  539. \zzdrawedge{\zzcnG=\zzcnC\divide\zzcnG by \zzcnE\relax
  540. \ifnum\zzcnG<1\relax\zzcnG=1\fi\zzcnE=\zzcnC\divide\zzcnE by \zzcnG\relax
  541. \ifnum#2=0\relax\advance\zzcnG by -1\fi}
  542. {\kern-1.39pt\raise-.76pt\hbox{.}}}
  543.  
  544. \def\drawsolidedge{\zzcnA=1\zzdmA=0pt\zzdmB=0pt
  545. \zzdrawedge{\zzcnG=0\zzcnD=\zzcnC}
  546. {\line(\xslope,\yslope){\zzcnD}}}
  547.  
  548. \def\zzdrawedge#1#2{\zzcheckedge{DRAW}\relax
  549. \ifnum\zzcnA=1\relax\zzcheckslope\xslope\yslope 6{SOLID OR DASHED EDGE}\fi
  550. \zzcnA=\xstart\zzcnB=\ystart\zzcnD=\zzdmA\zzcnE=\zzdmB\relax
  551. \ifnum\xslope=0\relax\zzcnC=\yend\advance\zzcnC by -\zzcnB\zzcnF=\yslope
  552. \else\zzcnC=\xend\advance\zzcnC by -\zzcnA\zzcnF=\xslope
  553. \zzdistance\xslope\yslope\relax
  554. \ifnum\xslope<0\relax\global\zzglobalcnA=-\zzglobalcnA\fi
  555. \multiply\zzcnD by 100\divide\zzcnD by \zzglobalcnA\multiply\zzcnD by \xslope
  556. \multiply\zzcnE by 100\divide\zzcnE by \zzglobalcnA\multiply\zzcnE by \xslope
  557. \fi
  558. \ifnum\zzcnF<0\relax\zzcnC=-\zzcnC\fi
  559. \ifnum\zzcnC>0\relax #1\relax
  560. \ifnum\zzcnF<0\relax\zzcnE=-\zzcnE\fi\zzcnF=\zzcnE\relax
  561. \ifnum\xslope=0\relax\zzcnE=0
  562. \else\multiply\zzcnF by \yslope\divide\zzcnF by \xslope\fi
  563. \zzmakepicture{\loop\put(\zzcnA,\zzcnB){#2}
  564. \ifnum\zzcnG>0\relax\advance\zzcnG by -1
  565. \advance\zzcnA by \zzcnE\advance\zzcnB by \zzcnF\repeat
  566. \zzrecordwidth\xstart\xstart\zzrecordwidth\xend\xend
  567. \zztotheight=\ystart\zztotdepth=\ystart\zzrecordheight\yend\yend}\fi}
  568.  
  569. %\drawedgehead draws an arrowhead along the current edge.
  570.  
  571. \def\drawedgehead#1#2#3{\zzcheckbool{#2}{SECOND}{DRAWEDGEHEAD}
  572. \zzcheckbool{#3}{THIRD}{DRAWEDGEHEAD}\zzcnB=#3
  573. \relax\ifnum#2=1\relax\zzcnA=#1\relax
  574. \zzdrawedgeheada\xstart\ystart\xend\yend\xslope\yslope
  575. \else\zzcnA=100\advance\zzcnA by -#1\relax
  576. \zzdrawedgeheada\xend\yend\xstart\ystart{-\xslope}{-\yslope}\fi}
  577.  
  578. %\zzcheckbool gives an error message unless its first argument is 1 or 0.
  579.  
  580. \def\zzcheckbool#1#2#3{
  581. \ifnum#1<0\errmessage{#2 PARAMETER OF #3 MUST BE 1 OR 0}\fi
  582. \ifnum#1>1\errmessage{#2 PARAMETER OF #3 MUST BE 1 OR 0}\fi}
  583.  
  584. \def\zzdrawedgeheada#1#2#3#4#5#6{\zzcheckedge{DRAW ARROWHEAD FOR}
  585. \zzcheckslope{#5}{#6}4{ARROWHEAD}
  586. \zzdmA=#3\advance\zzdmA by -#1
  587. \divide\zzdmA by 10\multiply\zzdmA by \zzcnA\divide\zzdmA by 10
  588. \zzdmB=#4\advance\zzdmB by -#2
  589. \divide\zzdmB by 10\multiply\zzdmB by \zzcnA\divide\zzdmB by 10
  590. \relax\ifnum\zzcnB=1\relax
  591. \zzdistance{#5}{#6}\zzdmC=\edgeheaddisp
  592. \multiply\zzdmC by 100\divide\zzdmC by \zzglobalcnA\zzdmD=\zzdmC
  593. \multiply\zzdmC by #5\multiply\zzdmD by #6
  594. \advance\zzdmA by \zzdmC\advance\zzdmB by \zzdmD\fi
  595. \advance\zzdmA by #1\zzcnA=\zzdmA\advance\zzdmB by #2\zzcnB=\zzdmB
  596. \zzmakepicture{\put(\zzcnA,\zzcnB){\vector(#5,#6){0}}
  597. \zzrecordwidth\zzdmA\zzdmA\zztotheight=\zzdmB\zztotdepth=\zzdmB}}
  598.  
  599. %\zzcheckslope gives an errormessage if the absolute value of #1 or #2
  600. %is greater than #3.
  601.  
  602. \def\zzcheckslope#1#2#3#4{\relax
  603. \ifnum#1>#3\zzcheckslopea{#1}{#2}{#4}\fi
  604. \ifnum#1<-#3\zzcheckslopea{#1}{#2}{#4}\fi
  605. \ifnum#2>#3\zzcheckslopea{#1}{#2}{#4}\fi
  606. \ifnum#2<-#3\zzcheckslopea{#1}{#2}{#4}\fi}
  607.  
  608. \def\zzcheckslopea#1#2#3{\errmessage{\the#1,\the#2 IS ILLEGAL SLOPE FOR #3}}
  609.  
  610. %The following macros each call \zzsetupbox{#2}{#3} and then issue the
  611. %resulting expression so that its shadow touches the edge x = \xslope.t
  612. %+\xstart, y = \yslope.t+\ystart. \abutX places the expression to the X
  613. %of the edge. For \abutleft and \abutright, #1 gives the y-coordinate
  614. %of the expression as an integer multiple of \diagramunit.  For \abutbelow
  615. %and \abutabove, #1 gives the x-coordinate similarly.  The macros \abutXd
  616. %are similar, except that #1 should be a dimension.
  617.  
  618. \def\abutleft#1:#2#3{\zzabut{#1}{#2}{#3}{-\yslope}{\zzslidehoriz}{1}}
  619. \def\abutright#1:#2#3{\zzabut{#1}{#2}{#3}{\yslope}{\zzslidehoriz}{1}}
  620. \def\abutbelow#1:#2#3{\zzabut{#1}{#2}{#3}{\xslope}{\zzslidevert}{1}}
  621. \def\abutabove#1:#2#3{\zzabut{#1}{#2}{#3}{-\xslope}{\zzslidevert}{1}}
  622.  
  623. \def\abutleftd#1#2#3{\zzabut{#1}{#2}{#3}{-\yslope}{\zzslidehoriz}{0}}
  624. \def\abutrightd#1#2#3{\zzabut{#1}{#2}{#3}{\yslope}{\zzslidehoriz}{0}}
  625. \def\abutbelowd#1#2#3{\zzabut{#1}{#2}{#3}{\xslope}{\zzslidevert}{0}}
  626. \def\abutaboved#1#2#3{\zzabut{#1}{#2}{#3}{-\xslope}{\zzslidevert}{0}}
  627.  
  628. \def\zzabut#1#2#3#4#5#6{\zzcheckedge{ABUT TO}
  629. \zzsetupbox{#2}{#3}\zzcnA=\xslope\zzcnB=\yslope
  630. \relax\ifnum#4<0\relax\zzcnA=-\zzcnA\zzcnB=-\zzcnB\fi
  631. \def\zzprocpoly{\zzclosestpoly}\def\zzprocrorect{\zzprocrorecta}
  632. \zzglobalshadow
  633. \advance\zzdmC by -\zzglobalxcenter\advance\zzdmD by -\zzglobalycenter
  634. \relax\ifnum#6=1\relax\zzmultdiagramunit\zzdmA{#1}\else\zzdmA=#1\fi
  635. \zzdmB=\zzdmA#5\relax\zzissue}
  636.  
  637. \def\zzslidehoriz{\relax\ifnum\yslope=0\errmessage
  638. {ABUTLEFT OR ABUTRIGHT ATTEMPTED FOR HORIZONTAL EDGE}\fi
  639. \advance\zzdmA by \zzdmD\advance\zzdmA by -\ystart
  640. \multiply\zzdmA by \xslope\divide\zzdmA by \yslope
  641. \advance\zzdmA by \xstart\advance\zzdmA by -\zzdmC}
  642.  
  643. \def\zzslidevert{\relax\ifnum\xslope=0\errmessage
  644. {ABUTBELOW OR ABUTABOVE ATTEMPTED FOR VERTICAL EDGE}\fi
  645. \advance\zzdmB by \zzdmC\advance\zzdmB by -\xstart
  646. \multiply\zzdmB by \yslope\divide\zzdmB by \xslope
  647. \advance\zzdmB by \ystart\advance\zzdmB by -\zzdmD}
  648.  
  649. %\zzclosestpoly finds the vertex of a convex polygon that is closest to a
  650. %directed line, x = xs.t+x0, y = ys.t+y0, assuming that the directed line
  651. %is to the left (right) of the polygon if ys is positive (negative)
  652. %and above (below) the polygon if xs is positive (negative).
  653. %It is called by defining \zzprocpoly to be \zzclosestpoly, setting \zzcnA,
  654. %\zzcnB to xs, ys, and executing \zzglobalshadow, which must have been
  655. %defined by a polygon descriptor.  The output is left in \zzdmC, \zzdmD.
  656.  
  657. \def\zzclosestpoly#1#2#3{\zzdmC=#1\zzdmD=#2\zzcnC=0\zzclosestpolya #3\end}
  658.  
  659. \def\zzclosestpolya#1{\def\zztesta{#1}\def\zztestb{\end}
  660. \ifx\zztesta\zztestb\let\zznext=\zzclosestpolyb
  661. \else\let\zznext=\zzclosestpolyc\fi\zznext {#1}}
  662.  
  663. \def\zzclosestpolyb#1{}
  664.  
  665. \def\zzclosestpolyc#1#2#3{\zzcnD=\zzcnB\multiply\zzcnD by #1\relax
  666. \zzcnE=\zzcnA\multiply\zzcnE by #2\relax\advance\zzcnD by -\zzcnE\relax
  667. \ifnum\zzcnD>0\relax
  668. \ifnum\zzcnC=1\let\zznext=\zzclosestpolyd
  669. \else\zzcnC=0\zzcastpolyd{#1}{#2}{#3}\let\zznext=\zzclosestpolya\fi
  670. \else\zzcnC=1\zzcastpolyd{#1}{#2}{#3}\let\zznext=\zzclosestpolya\fi
  671. \zznext}
  672.  
  673. \def\zzclosestpolyd#1\end{}
  674.  
  675. %\setcircle initializes \dcircle, \xcircle, and \ycircle to its first
  676. %three parameters, and sets \zziscircle to 1.
  677.  
  678. \def\setcircle#1#2#3{\dcircle=#1\xcircle=#2\ycircle=#3\zziscircle=1}
  679.  
  680. %\shiftcircle#1#2 displaces \xcircle, \ycircle by #1, #2.
  681.  
  682. \def\shiftcircle#1#2{\zzcheckcircle{SHIFT}
  683. \advance\xcircle by #1\advance\ycircle by #2}
  684.  
  685. \def\zzcheckcircle#1{\relax\ifnum\zziscircle=0\errmessage
  686. {ATTEMPT TO #1 NONEXISTENT CIRCLE}\fi}
  687.  
  688. %\drawcircle draws quadrants of the current circle.
  689.  
  690. \def\drawcircle#1#2#3#4{\zzcheckcircle{DRAW}\zzdmA=\dcircle\divide\zzdmA by 2
  691. \zzmakepicture{\zzcnA=\dcircle\zzcnB=\xcircle\zzcnC=\ycircle
  692. \zztotheight=\ycircle\zztotdepth=\ycircle
  693. \zzrecordwidth\xcircle\xcircle\relax
  694. \zzdrawcirclea{#1}{tr}{\zzdmA}{\zzdmA}\zzdrawcirclea{#2}{br}{\zzdmA}{-\zzdmA}
  695. \zzdrawcirclea{#3}{bl}{-\zzdmA}{-\zzdmA}
  696. \zzdrawcirclea{#4}{tl}{-\zzdmA}{\zzdmA}}}
  697.  
  698. \def\zzdrawcirclea#1#2#3#4{\zzcheckbool{#1}{}{DRAWCIRCLE}\ifnum#1=1\relax
  699. \put(\zzcnB,\zzcnC){\oval(\zzcnA,\zzcnA)[#2]}
  700. \zzdmB=\xcircle\advance\zzdmB by #3\zzrecordwidth\zzdmB\zzdmB
  701. \zzdmB=\ycircle\advance\zzdmB by #4\zzrecordheight\zzdmB\zzdmB\fi}
  702.  
  703. %\drawcirclehead issues an arrowhead placed on the current circle.
  704.  
  705. \def\drawcirclehead#1#2#3{\zzcheckcircle{DRAW ARROWHEAD FOR}
  706. \zzreduceterms{#1}{#2}{0,0 ARE ILLEGAL PARAMETERS FOR DRAWCIRCLEHEAD}
  707. \zzdistance{\zzcnC}{\zzcnD}\zzcheckbool{#3}{THIRD}{DRAWCIRCLEHEAD}
  708. \ifnum#3=1\relax\zzcnA=\zzcnD\zzcnB=-\zzcnC\else\zzcnA=-\zzcnD\zzcnB=\zzcnC\fi
  709. \zzdmA=\dcircle\multiply\zzdmA by 50\divide\zzdmA by \zzglobalcnA
  710. \zzdmB=\circleheaddisp\multiply\zzdmB by 100\divide\zzdmB by \zzglobalcnA
  711. \zzdmE=\zzdmA\multiply\zzdmE by \zzcnC\zzdmC=\xcircle\advance\zzdmC by \zzdmE
  712. \zzdmE=\zzdmB\multiply\zzdmE by \zzcnA\advance\zzdmC by \zzdmE
  713. \zzdmE=\zzdmA\multiply\zzdmE by \zzcnD\zzdmD=\ycircle\advance\zzdmD by \zzdmE
  714. \zzdmE=\zzdmB\multiply\zzdmE by \zzcnB\advance\zzdmD by \zzdmE
  715. \zzcnC=\zzdmC\zzcnD=\zzdmD\zzcheckslope\zzcnA\zzcnB4{ARROWHEAD}
  716. \zzmakepicture{\put(\zzcnC,\zzcnD){\vector(\zzcnA,\zzcnB){0}}
  717. \zzrecordwidth\zzdmC\zzdmC\zztotheight=\zzdmD\zztotdepth=\zzdmD}}
  718.  
  719. %The next four macros cause an expression to be abutted to the current
  720. %circle.
  721.  
  722. \def\abutcircleleft#1#2#3{\zzabutcircle{#1}{#2}{#3}{}
  723. \zzslidehoriz{\relax\ifdim\zzdmA>\zzdmH\relax\zzdmH=\zzdmA\fi}}
  724.  
  725. \def\abutcircleright#1#2#3{\zzabutcircle{#1}{#2}{#3}{\zzrotate\zzrotate}
  726. \zzslidehoriz{\relax\ifdim\zzdmA<\zzdmH\relax\zzdmH=\zzdmA\fi}}
  727.  
  728. \def\abutcirclebelow#1#2#3{\zzabutcircle{#1}{#2}{#3}{\zzrotate}
  729. \zzslidevert{\relax\ifdim\zzdmB>\zzdmI\relax\zzdmI=\zzdmB\fi}}
  730.  
  731. \def\abutcircleabove#1#2#3{\zzabutcircle
  732. {#1}{#2}{#3}{\zzrotate\zzrotate\zzrotate}
  733. \zzslidevert{\relax\ifdim\zzdmB<\zzdmI\relax\zzdmI=\zzdmB\fi}}
  734.  
  735. \def\zzabutcircle#1#2#3#4#5#6{\zzcheckcircle{ABUT TO}
  736. \zzsetupbox{#2}{#3}\def\zzprocpoly{\zzclosestpoly}
  737. \def\zzprocrorect{\zzprocrorecta}
  738. \zzdmF=\dcircle\divide\zzdmF by 2
  739. \zzdmG=\dcircle\multiply\zzdmG by 100\divide\zzdmG by 283
  740. \xstart=-\zzdmF\ystart=0pt\xslope=0\yslope=-1
  741. \zzabutcirclea{#1}{#4}{#5}\zzdmH=\zzdmA\zzdmI=\zzdmB
  742. \xstart=-\zzdmG\ystart=\zzdmG\xslope=-1\yslope=-1
  743. \zzabutcirclea{#1}{#4}{#5}#6\relax
  744. \xstart=-\zzdmG\ystart=-\zzdmG\xslope=1\yslope=-1
  745. \zzabutcirclea{#1}{#4}{#5}#6\relax
  746. \zzdmA=\zzdmH\advance\zzdmA by \xcircle
  747. \zzdmB=\zzdmI\advance\zzdmB by \ycircle
  748. \zzissue}
  749.  
  750. \def\zzabutcirclea#1#2#3{#2\relax
  751. \zzcnA=\xslope\zzcnB=\yslope
  752. \zzglobalshadow
  753. \advance\zzdmC by -\zzglobalxcenter\advance\zzdmD by -\zzglobalycenter
  754. \zzdmA=#1\zzdmB=\zzdmA #3\relax}
  755.  
  756. \def\zzrotate{\zzdmE=\xstart\xstart=-\ystart\ystart=\zzdmE
  757. \zzcnC=\xslope\xslope=-\yslope\yslope=\zzcnC}
  758.  
  759. %MACROS FOR CATEGORY-THEORY DIAGRAMS
  760.  
  761. %The following control symbols may be redefined by the user:
  762. \def\ctvertexstyle{\displaystyle}
  763. \def\ctabutstyle{\textstyle}
  764. \def\ctvertexborderlr{3pt}
  765. \def\ctvertexbordertb{4pt}
  766. \def\ctloopdiameter{20pt}
  767. \def\ctabutcircledisp{5pt}
  768. \def\ctabutborderlr{2pt}
  769. \def\ctabutbordertb{2pt}
  770. \def\ctabutborderinset{3pt}
  771. \def\ctabutborderinsetdouble{6pt}%Must be twice \ctabutborderinset
  772. \def\ctdoubleedgedisp{2pt}
  773.  
  774. %The following registers are used locally:
  775. \newdimen\zzdmX\newdimen\zzdmY
  776.  
  777. %Hidden macros and other defined control symbols:
  778. %    used by \ctdiagram: \diagram\ctsolid\cthead
  779. %    used by \ctv and \ctvg: \vertex\border\rect
  780. %    used by \ctgl: \leftghost
  781. %    used by \ctgr: \rightghost
  782. %    used by \ctlptl, \ctlptlcc, \ctlptr, \ctlptrcc, \ctlpbr, \ctlpbrcc,
  783. %    \ctlpbl, \ctlpblcc: \zzctlp\border\setcircle\shiftcircle\drawcircle
  784. %        \drawcirclehead\abutcircleleft\abutcircleright\zzctabutprog
  785. %        \octagon
  786. %    used by \cten, \ctet, \cteb, \ctel, \cter, \ctetg, \ctebg, \ctelg, \cterg,
  787. %    \ctetb, \ctelr, \ctetbg, \ctelrg: \setedge\zzctxmean\zzctymean
  788. %        \zzmultdiagramunit\zzcte\zzctee\shadeedge\abutaboved\abutbelowd
  789. %        \abutleftd\abutrightd\zzctabutprog\border\octagon\shiftedge
  790. %        \drawsolidedge\zzctdrawdashedge\drawdashedge\zzctdrawdotedge
  791. %        \drawdotedge\zzctdrawedgehead\drawedgehead\zzctnodrawedgehead
  792. %    multiply defined control symbols: \zzctdrawedge\zzctdrawhead
  793. %        \zzctxmeanadj\zzctymeanadj
  794.  
  795. %\ctdiagram is similar to \diagram, except that it executes \ctsolid and
  796. %\cthead before the expression program #1.
  797.  
  798. \def\ctdiagram#1{\diagram{\ctsolid\cthead\ctoutermid #1}}
  799.  
  800. %\ctvg is similar to \vertex except that the expression #3 is printed in
  801. %\ctvertexstyle mode, and the expression program #4 is followed by a
  802. %standard program that borders the current rectangle by \ctvertexborderlr
  803. %on the sides and \ctvertexbordertb on the top and bottom, and then
  804. %creates a rectangular shadow.  \ctv is similar to \ctvg except that the
  805. %expression program is empty (except for the standard program).
  806.  
  807. \def\ctvg#1,#2:#3#4{\vertex #1,#2:{\ctvertexstyle #3}{#4\relax
  808. \border\ctvertexborderlr\ctvertexbordertb\rect}}
  809.  
  810. \def\ctv#1,#2:#3{\ctvg #1,#2:{#3}{}}
  811.  
  812. %\ctgl and \ctgr are similar to \leftghost and \rightghost except that
  813. %the expression #1 is printed in \ctvertexstyle.
  814.  
  815. \def\ctgl#1{\leftghost{\ctvertexstyle #1}}
  816.  
  817. \def\ctgr#1{\rightghost{\ctvertexstyle #1}}
  818.  
  819. %The following eight macros print a three-quarter-circle loop of diameter
  820. %\ctloopdiameter at one of the corners of an expanded current rectangle,
  821. %with an arrowhead at one end of the loop.
  822.  
  823. \def\ctlptl#1{\zzctlp{\lexpr\texpr}{{0pt}\circleheaddisp}{1011}{101}
  824. {\abutcircleleft\ctabutcircledisp}{#1}}
  825.  
  826. \def\ctlptlcc#1{\zzctlp{\lexpr\texpr}{{-\circleheaddisp}{0pt}}{1011}{0{-1}0}
  827. {\abutcircleleft\ctabutcircledisp}{#1}}
  828.  
  829. \def\ctlptr#1{\zzctlp{\rexpr\texpr}{\circleheaddisp{0pt}}{1101}{0{-1}1}
  830. {\abutcircleright\ctabutcircledisp}{#1}}
  831.  
  832. \def\ctlptrcc#1{\zzctlp{\rexpr\texpr}{{0pt}\circleheaddisp}{1101}{{-1}00}
  833. {\abutcircleright\ctabutcircledisp}{#1}}
  834.  
  835. \def\ctlpbr#1{\zzctlp{\rexpr\bexpr}{{0pt}{-\circleheaddisp}}{1110}{{-1}01}
  836. {\abutcircleright{-\ctabutcircledisp}}{#1}}
  837.  
  838. \def\ctlpbrcc#1{\zzctlp{\rexpr\bexpr}{\circleheaddisp{0pt}}{1110}{010}
  839. {\abutcircleright{-\ctabutcircledisp}}{#1}}
  840.  
  841. \def\ctlpbl#1{\zzctlp{\lexpr\bexpr}{{-\circleheaddisp}{0pt}}{0111}{011}
  842. {\abutcircleleft{-\ctabutcircledisp}}{#1}}
  843.  
  844. \def\ctlpblcc#1{\zzctlp{\lexpr\bexpr}{{0pt}{-\circleheaddisp}}{0111}{100}
  845. {\abutcircleleft{-\ctabutcircledisp}}{#1}}
  846.  
  847. \def\zzctlp#1#2#3#4#5#6{\border\ctvertexborderlr\ctvertexbordertb
  848. \setcircle\ctloopdiameter #1
  849. \border{-\ctvertexborderlr}{-\ctvertexbordertb}
  850. \shiftcircle #2\drawcircle #3\drawcirclehead #4
  851. #5{\ctabutstyle #6}\zzctabutprog}
  852.  
  853. \def\zzctabutprog{\border\ctabutborderlr\ctabutbordertb
  854. \borderto{\ctabutborderinsetdouble}{\ctabutborderinsetdouble}
  855. \octagon\ctabutborderinset}
  856.  
  857. %\cten#1,#2,#3,#4: draws a shaded edge from #1,#2 to #3,#4, possibly with
  858. %an arrowhead at its end.
  859.  
  860. \def\cten#1:{\setedge#1:\shadeedge\zzctdrawedge\zzctdrawhead1}
  861.  
  862. %The following four macros draw a shaded edge, possibly with an arrowhead
  863. %at the end, and abut an expression to the edge at its midpoint.
  864.  
  865. \def\ctet#1:#2{\setedge#1:\zzctxmean\zzcte\abutaboved{#2}\zzctxmeanadj}
  866.  
  867. \def\cteb#1:#2{\setedge#1:\zzctxmean\zzcte\abutbelowd{#2}\zzctxmeanadj}
  868.  
  869. \def\ctel#1:#2{\setedge#1:\zzctymean\zzcte\abutleftd{#2}\zzctymeanadj}
  870.  
  871. \def\cter#1:#2{\setedge#1:\zzctymean\zzcte\abutrightd{#2}\zzctymeanadj}
  872.  
  873. \def\zzctxmean{\zzdmX=\xstart\advance\zzdmX by \xend\divide\zzdmX by 2}
  874.  
  875. \def\zzctymean{\zzdmX=\ystart\advance\zzdmX by \yend\divide\zzdmX by 2}
  876.  
  877. \def\zzcte#1#2#3{\shadeedge #3\zzctdrawedge\zzctdrawhead1
  878. #1\zzdmX{\ctabutstyle #2}\zzctabutprog}
  879.  
  880. %The next four macros behave similarly to those above, but abut an
  881. %expression to a specified point on the edge.
  882.  
  883. \def\ctetg#1;#2:#3{\setedge#1:\zzmultdiagramunit\zzdmX{#2}\zzcte
  884. \abutaboved{#3}\relax}
  885.  
  886. \def\ctebg#1;#2:#3{\setedge#1:\zzmultdiagramunit\zzdmX{#2}\zzcte
  887. \abutbelowd{#3}\relax}
  888.  
  889. \def\ctelg#1;#2:#3{\setedge#1:\zzmultdiagramunit\zzdmX{#2}\zzcte
  890. \abutleftd{#3}\relax}
  891.  
  892. \def\cterg#1;#2:#3{\setedge#1:\zzmultdiagramunit\zzdmX{#2}\zzcte
  893. \abutrightd{#3}\relax}
  894.  
  895. %\ctetb (\ctelr) draws a pair of shaded edges, with two expressions
  896. %abutted to the top and bottom (left and right) of the midpoint.
  897. %\ctetbg and \ctelrg are similar, but abut to a specified point on the edge.
  898.  
  899. \def\ctetb#1:#2#3#4#5{\zzcheckbool{#2}{FIFTH}{CTETB}
  900. \zzcheckbool{#3}{SIXTH}{CTETB}
  901. \setedge#1:\zzctxmean\zzctee\xslope\abutaboved\abutbelowd
  902. {#2}{#3}{#4}{#5}\zzctxmeanadj}
  903.  
  904. \def\ctelr#1:#2#3#4#5{\zzcheckbool{#2}{FIFTH}{CTELR}
  905. \zzcheckbool{#3}{SIXTH}{CTELR}
  906. \setedge#1:\zzctymean\zzctee\yslope\abutleftd\abutrightd
  907. {#2}{#3}{#4}{#5}\zzctymeanadj}
  908.  
  909. \def\ctetbg#1;#2,#3:#4#5#6#7{\zzcheckbool{#4}{SEVENTH}{CTETBG}
  910. \zzcheckbool{#5}{EIGHTH}{CTETBG}\setedge#1:\zzmultdiagramunit\zzdmX{#2}
  911. \zzctee\xslope
  912. \abutaboved{\zzmultdiagramunit\zzdmX{#3}\abutbelowd}{#4}{#5}{#6}{#7}\relax}
  913.  
  914. \def\ctelrg#1;#2,#3:#4#5#6#7{\zzcheckbool{#4}{SEVENTH}{CTELRG}
  915. \zzcheckbool{#5}{EIGHTH}{CTELRG}\setedge#1:\zzmultdiagramunit\zzdmX{#2}
  916. \zzctee\yslope
  917. \abutleftd{\zzmultdiagramunit\zzdmX{#3}\abutrightd}{#4}{#5}{#6}{#7}\relax}
  918.  
  919. \def\zzctee#1#2#3#4#5#6#7#8{
  920. \ifnum#1>0\relax\zzdmY=\ctdoubleedgedisp\else\zzdmY=-\ctdoubleedgedisp\fi
  921. \shiftedge\zzdmY\shadeedge #8\zzctdrawedge\zzctdrawhead{#4}
  922. #2\zzdmX{\ctabutstyle #6}\zzctabutprog
  923. \multiply\zzdmY by -2\relax
  924. \shiftedge\zzdmY\shadeedge #8\zzctdrawedge\zzctdrawhead{#5}
  925. #3\zzdmX{\ctabutstyle #7}\zzctabutprog}
  926.  
  927. %\ctinnermid defines \zzctxmeanadj and \zzctymeanadj so that \ctet, \cteb,
  928. %\ctel, \cter, \ctetb, and \ctelr recompute the midpoint of the current
  929. %edge after shading.  \ctoutermid defines these control symbols so that
  930. %these routines do not recompute the midpoint.
  931.  
  932. \def\ctinnermid{\def\zzctxmeanadj{\zzctxmean}\def\zzctymeanadj{\zzctymean}}
  933.  
  934. \def\ctoutermid{\def\zzctxmeanadj{\relax}\def\zzctymeanadj{\relax}}
  935.  
  936. %\zzctdrawdashedge draws a dashed edge.
  937.  
  938. \def\zzctdrawdashedge{\relax
  939. \ifnum\xslope=0\relax\drawdashedge{7pt}{7pt}11
  940. \else\ifnum\yslope=0\relax\drawdashedge{7pt}{7pt}11
  941. \else\drawdashedge{15pt}{7pt}01\fi\fi}
  942.  
  943. %\zzctdrawdotedge draws a dotted edge.
  944.  
  945. \def\zzctdrawdotedge{\drawdotedge{8pt}1}
  946.  
  947. %\ctsolid (\ctdash,\ctdot) defines \zzctdrawedge to be \drawsolidedge
  948. %(\zzctdrawdashedge,\zzctdrawdotedge), so that edges will be solid
  949. %(dashed, dotted).
  950.  
  951. \def\ctsolid{\def\zzctdrawedge{\drawsolidedge}}
  952.  
  953. \def\ctdash{\def\zzctdrawedge{\zzctdrawdashedge}}
  954.  
  955. \def\ctdot{\def\zzctdrawedge{\zzctdrawdotedge}}
  956.  
  957. %\zzctdrawedgehead places a forward-pointing arrowhead at the end of an edge
  958. %if #1=1 or a backward-pointing arrowhead at the beginning if #1=0.
  959. %\zzctnodrawedgehead is called in the same way but does nothing.
  960.  
  961. \def\zzctdrawedgehead#1{\relax\ifnum#1=1\relax
  962. \drawedgehead{100}10\else\drawedgehead{0}00\fi}
  963.  
  964. \def\zzctnodrawedgehead#1{}
  965.  
  966. %\cthead (\ctnohead) defines \zzctdrawhead to be \zzctdrawedgehead
  967. %(\zzctnodrawedgehead), so that edges will (will not) have arrowheads.
  968.  
  969. \def\cthead{\def\zzctdrawhead{\zzctdrawedgehead}}
  970.  
  971. \def\ctnohead{\def\zzctdrawhead{\zzctnodrawedgehead}}
  972.